package com.core.gwt.place.client;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.user.client.Window;

/**
 * Manages the current {@link Mode}.<br>
 * 

 * 
 */
public class ModeManager {
	private class ModeWrapper {
		private final Mode mode;

		private final Mode.Handler handler = new Mode.Handler() {
			@Override
			public void onExit() {
				if (ModeWrapper.this.equals(currentMode)) {
					currentMode = null;
				}
			}
		};

		public ModeWrapper(final Mode mode) {
			this.mode = mode;
		}

		public void cancel() {
			mode.cancel();
		}

		public void enter() {
			mode.enter(handler);
		}

		public String mayCancel() {
			return mode.mayCancel();
		}
	}

	private ModeWrapper currentMode;

	/**
	 * Cancels the current mode, if any.
	 * 
	 * @return <code>true</code> if the mode is canceled or if there was no
	 *         current mode; <code>false</code> if the current mode refuses to
	 *         cancel
	 */
	public boolean cancelMode() {
		boolean result = false;
		if (maySwitchMode()) {
			result = true;
		}
		return result;
	}

	/**
	 * Enters an {@link Mode}, only after successfully canceling the
	 * previous mode, if any.
	 * 
	 * @return <code>true</code> if the mode is entered; <code>false</code> if
	 *         there's a previous mode and it refuses to cancel
	 */
	public boolean enterMode(final Mode mode) {
		boolean result = false;
		if (maySwitchMode()) {
			currentMode = new ModeWrapper(mode);
			currentMode.enter();
			result = true;
		}
		return result;
	}

	/**
	 * Call this method from your implementation of {@link Activity#mayStop()}
	 * to ensure that the current mode, if any, gets a chance to warn the user
	 * of unsaved changes.
	 */
	public String mayStop() {
		String result = null;
		if (currentMode != null) {
			result = currentMode.mayCancel();
		}
		return result;
	}

	/**
	 * Call this method from your implementation of {@link Activity#onCancel()}
	 * to ensure that the current mode, if any, is canceled.
	 */
	public void onCancel() {
		exitMode();
	}

	/**
	 * Call this method from your implementation of {@link Activity#onStop()} to
	 * ensure that the current mode, if any, is canceled.
	 */
	public void onStop() {
		exitMode();
	}

	private boolean confirm(final String message) {
		return Window.confirm(message);
	}

	private void exitMode() {
		if (currentMode != null) {
			currentMode.cancel();
			currentMode = null;
		}
	}

	private boolean maySwitchMode() {
		boolean okay = true;
		if (currentMode != null) {
			final String warning = currentMode.mayCancel();
			okay = (warning != null) ? confirm(warning) : true;
			if (okay) {
				currentMode.cancel();
				currentMode = null;
			}
		}
		return okay;
	}
}
